package com.lhkj.ct.framework.config;

import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.lhkj.ct.base.enums.IBaseEnum;
import com.lhkj.ct.base.exception.BusinessException;
import com.lhkj.ct.base.json.MyLocalDateTimeDeserializer;
import com.lhkj.ct.base.json.MyLocalTimeDeserializer;
import com.lhkj.ct.base.json.databind.BaseEnumDeserializer;
import com.lhkj.ct.base.json.databind.BaseEnumWritingByMapSerializer;
import com.lhkj.ct.base.json.databind.IEnumSerializer;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.type.filter.AssignableTypeFilter;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;
import java.util.regex.Pattern;

@Configuration
public class JacksonConfigure {

    /**
     * DateTime格式化字符串
     */
    private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * Date格式化字符串
     */
    private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";

    /**
     * Time格式化字符串
     */
    private static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";


    /**
     * 校验字符串是否符合yyyy-MM日期格式
     */
    private static final Pattern YYYY_MM_PATTERN = Pattern.compile("^\\d{4}-\\d{2}$");

    /**
     * 校验字符串是否符合yyyy-MM-dd日期格式
     */
    private static final Pattern DATE_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");

    /**
     * 校验字符串是否符合HH:mm时间格式
     */
    private static final Pattern HH_MM_PATTERN = Pattern.compile("^\\d{2}:\\d{2}$");

    /**
     * 校验字符串是否符合yyyy-MM-dd HH:mm:ss日期时间格式
     */
    private static final Pattern DATETIME_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$");

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer enumCustomizer() {
        return jacksonObjectMapperBuilder -> {
            //自定义序列化器注入
            jacksonObjectMapperBuilder.serializerByType(IBaseEnum.class, new BaseEnumWritingByMapSerializer());
            jacksonObjectMapperBuilder.serializerByType(IEnum.class,  new IEnumSerializer());

            //扫描枚举所在的包
            ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
            provider.addIncludeFilter(new AssignableTypeFilter(IBaseEnum.class));
            provider.addIncludeFilter(new AssignableTypeFilter(IEnum.class));
            Set<BeanDefinition> components = provider.findCandidateComponents("com.lhkj.ct.**.enums");
//            Map<Class<?>, JsonDeserializer<?>> deserializers = new LinkedHashMap<>();
            // 自定义反序列化器注入
            for (BeanDefinition component : components) {
                try {
                    Class<?> cls = Class.forName(component.getBeanClassName());
                    if (cls.isEnum() && (IBaseEnum.class.isAssignableFrom(cls) || IEnum.class.isAssignableFrom(cls))) {
                        @SuppressWarnings({"rawtypes", "unchecked"})
                        Class<IEnum> baseEnumClass = (Class<IEnum>) cls;
                        //自定义反序列化器注入
//                        deserializers.put(cls, new BaseEnumDeserializer(baseEnumClass));
                        jacksonObjectMapperBuilder.deserializerByType(cls, new BaseEnumDeserializer(baseEnumClass));
                    }
                } catch (ClassNotFoundException e) {
                    // fixme 这里待修改
                    throw new BusinessException(400, e.getMessage());
                }
            }
//            jacksonObjectMapperBuilder.deserializersByType(deserializers);

        };
    }

    /**
     * Jackson序列化和反序列化转换器，用于转换Post请求体中的json以及将对象序列化为返回响应的json
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> builder
                .serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)))
                .serializerByType(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)))
                .serializerByType(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN)))
//                .serializerByType(Date.class, new DateSerializer(false, new SimpleDateFormat(DEFAULT_DATETIME_PATTERN)))
                .deserializerByType(LocalDateTime.class, new MyLocalDateTimeDeserializer())
                .deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)))
                .deserializerByType(LocalTime.class, new MyLocalTimeDeserializer())
//                .deserializerByType(Date.class, new DateDeserializers.DateDeserializer(DateDeserializers.DateDeserializer.instance, new SimpleDateFormat(DEFAULT_DATETIME_PATTERN), DEFAULT_DATETIME_PATTERN))
                ;
    }

    /**
     * LocalDate转换器，用于转换RequestParam和PathVariable参数
     */
    @Bean
    public Converter<String, LocalDate> localDateConverter() {
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                if (YYYY_MM_PATTERN.matcher(source).matches()){
                    return LocalDate.parse(source + "-01", DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN));
                }
                return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN));
            }
        };
    }

//
//    /**
//     * LocalDateTime转换器，用于转换RequestParam和PathVariable参数
//     */
//    @Bean
//    public Converter<String, LocalDateTime> localDateTimeConverter() {
//        return new Converter<String, LocalDateTime>() {
//            @Override
//            public LocalDateTime convert(String source) {
//                return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN));
//            }
//        };
//    }
//
    /**
     * LocalTime转换器，用于转换RequestParam和PathVariable参数
     */
//    @Bean
//    public Converter<String, LocalTime> localTimeConverter() {
//        return new Converter<String, LocalTime>() {
//            @Override
//            public LocalTime convert(String source) {
//                if (HH_MM_PATTERN.matcher(source).matches()){
//                    return LocalTime.parse(source +":00", DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN));
//                }
//                return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN));
//            }
//        };
//    }
//
//    /**
//     * Date转换器，用于转换RequestParam和PathVariable参数
//     */
//    @Bean
//    public Converter<String, Date> dateConverter() {
//        return new Converter<String, Date>() {
//            @Override
//            public Date convert(String source) {
//                final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DEFAULT_DATETIME_PATTERN);
//
//                try {
//                    return simpleDateFormat.parse(source);
//                } catch (ParseException e) {
//                    logger.error("Init Converter String to Date error!", e);
//                    throw new RuntimeException(e);
//                }
//            }
//        };
//    }

}
